package com.bsj.power.pls.config.net.netty.protocol;

import com.bsj.tools.HexStr;
import lombok.extern.slf4j.Slf4j;

/**
 * @author yinhao
 * @version 1.0
 * @description
 * @date 2024/9/23
 */
@Slf4j
public class UWBPacketUtil {

    /**
     * 找包头
     * @param data
     * @param offset
     * @return
     */
    public static int getPosHead(byte[] data, int offset) {
        int posHead = -1;
        int length = data.length;
        if (offset >= length) {
            return posHead;
        }

        for (int i = offset; i < data.length; i++) {
            byte tem = data[i];
            if (i == data.length - 1) {
                break;
            }
            if (tem == 0x24) {
                posHead = i;
                break;
            }
        }
        return posHead;
    }

    /**
     * @param data   数据
     * @param offset 命令单元开始索引
     * @param bodyLen 内容长度
     * @return
     * @Description 校验结果
     **/
    public static boolean getCheckResult(byte[] data, int offset, int bodyLen) {
        if (data == null) {
            return false;
        }
        //整个数据包的长度
        int len = offset + 1 + 1 + bodyLen + 1 + 1;
        if (data.length < len) {
            byte[] err = new byte[data.length - offset];
            System.arraycopy(data, offset, err, 0, data.length - offset);
            log.info("[UWB24]Packet length is failure : {}", HexStr.toStr(err));
            return false;
        }
        //从包头开始一直到异或校验位
        int xorA = CheckXor(data, offset - 1, len - 2);
        int xor = Byte.toUnsignedInt(data[len - 2]);
        if (xorA != xor) {
            log.info("[UWB24]Packet xor error,获取到的数据为：{}", HexStr.toStr(data));
            return false;
        }
        return true;
    }

    /**
     * @param data     数据
     * @param offset   命令单元所对应的索引
     * @param data_len 检验的长度
     * @return
     * @Description 校验码
     **/
    public static int CheckXor(byte[] data, int offset, int data_len) {
        int n = 0;
        if (data == null) {
            return n;
        }
        int len = 0;
        if (data_len <= data.length) {
            len = data_len;
        } else {
            len = offset + data_len;
        }
        for (int i = offset; i < len; i++) {
            n ^= data[i];
        }
        return n & 0xFF;
    }

    /**
     * 检查数据
     *
     * @param data
     * @param data_offset
     * @param data_len
     * @return
     */
    public static boolean checkPacket(byte[] data, int data_offset, int data_len) {
        if (data == null) {
            return false;
        }
        // 校验头
        if (data[data_offset] != 0x24) {
            return false;
        }
        //返回一个不包含头的数据包
        byte[] esc_pack = new byte[data_len - 1];
        System.arraycopy(data, 1, esc_pack, 0, data_len - 1);
        int len = esc_pack.length;
        //最少5个字节
        if (len < 5) {
            return false;
        }
        int offset = 0;
        //校验位
        int xor = esc_pack[len - 1] & 0xFF;
        int xorA = CheckXor(esc_pack, offset, len - 1);
        if (xor != xorA) {
            return false;
        }
        //解析包
        fromPacket(esc_pack, offset);
        return true;
    }

    /**
     * @param esc_data    需要解析的数据
     * @param data_offset 数据起始索引
     * @return
     * @Description 解析包
     **/
    public static void fromPacket(byte[] esc_data, int data_offset){
        int offset = data_offset;
        //消息体长度
        int length = 0;
        if (esc_data != null) {
            int len = esc_data.length;
            // 指令类别
            int cmdType = 0;
            if (offset + 1 <= len) {
                cmdType = Byte.toUnsignedInt(esc_data[offset]);
            }
            offset += 1;
            //消息包长度
            if (offset + 1 <= len) {
                length = Byte.toUnsignedInt(esc_data[offset]);
            }
            offset += 1;
            //消息体
            byte[] contentBytes = new byte[length - 2];
            System.arraycopy(esc_data, offset, contentBytes, 0, length - 2);
            switch (cmdType) {
                case 0xEF:
                    //终端参数设置时的主机应答数据
                    break;
                case 0xEE:
                    //查询终端参数主机应答（充电柜查询电量和UID）
                    break;
                case 0xED:
                    //调度指令下发的主机应答
                    break;
                case 0xEC:
                    //下发声光报警的主机应答
                    break;
                case 0xE9:
                    //经纬度状态信息及报警信息上报
                default:
                    break;
            }
        }
    }
}
